Add more safeguards around odd filenames
authorAlex Crichton <alex@alexcrichton.com>
Wed, 4 Nov 2015 21:11:19 +0000 (13:11 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 4 Nov 2015 21:11:19 +0000 (13:11 -0800)
This commit is targeted at fixing #2102 via two routes:

1. The dependency on `tar` was upgraded to include more contextual information
   in error messages about why the unpack failed. This should help diagnose
   these sorts of issues that happen in the first place.
2. Packaging crates that have files with odd filenames is no longer allowed.
   An error is returned indicating that the files cannot be packaged as they're
   not cross platform. The currently rejected set of files are non-utf8
   filenames (already present) and those containing characters special on
   Windows.

Closes #2102

Cargo.lock
src/cargo/ops/cargo_package.rs
tests/test_cargo_package.rs

index d0e49fbfd1e292d21124a28f58fe9052acbddfdc..2c46314bf9cf02172105d6ff6df20717acccf25b 100644 (file)
@@ -23,7 +23,7 @@ dependencies = [
  "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -200,6 +200,11 @@ name = "libc"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "libc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "libgit2-sys"
 version = "0.3.6"
@@ -356,11 +361,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "tar"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "filetime 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
index e08281814b197dc8f39cf93bd10311319af23ed0..635aaf5c34ec7caf7af1941deb73e51dd2e10cdd 100644 (file)
@@ -155,6 +155,7 @@ fn tar(pkg: &Package, src: &PathSource, config: &Config,
     for file in try!(src.list_files(pkg)).iter() {
         if &**file == dst { continue }
         let relative = util::without_prefix(&file, &root).unwrap();
+        try!(check_filename(relative));
         let relative = try!(relative.to_str().chain_error(|| {
             human(format!("non-utf8 path in source directory: {}",
                           relative.display()))
@@ -224,3 +225,30 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path)
 
     Ok(())
 }
+
+// It can often be the case that files of a particular name on one platform
+// can't actually be created on another platform. For example files with colons
+// in the name are allowed on Unix but not on Windows.
+//
+// To help out in situations like this, issue about weird filenames when
+// packaging as a "heads up" that something may not work on other platforms.
+fn check_filename(file: &Path) -> CargoResult<()> {
+    let name = match file.file_name() {
+        Some(name) => name,
+        None => return Ok(()),
+    };
+    let name = match name.to_str() {
+        Some(name) => name,
+        None => {
+            return Err(human(format!("path does not have a unicode filename \
+                                      which may not unpack on all platforms: {}",
+                                     file.display())))
+        }
+    };
+    let bad_chars = ['/', '\\', '<', '>', ':', '"', '|', '?', '*'];
+    for c in bad_chars.iter().filter(|c| name.contains(**c)) {
+        return Err(human(format!("cannot package a filename with a special \
+                                  character `{}`: {}", c, file.display())))
+    }
+    Ok(())
+}
index 6e59a364773b0089ca523b3ebc59e5d120ef9885..5088d1ce2ec10bd2071bbada3cf7ade698b9965c 100644 (file)
@@ -427,3 +427,27 @@ src[..]main.rs
                 "unexpected filename: {:?}", f.header().path())
     }
 });
+
+#[cfg(unix)] // windows doesn't allow these characters in filenames
+test!(package_weird_characters {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+        "#)
+        .file("src/main.rs", r#"
+            fn main() { println!("hello"); }
+        "#)
+        .file("src/:foo", "");
+
+    assert_that(p.cargo_process("package"),
+                execs().with_status(101).with_stderr("\
+warning: [..]
+failed to prepare local package for uploading
+
+Caused by:
+  cannot package a filename with a special character `:`: src/:foo
+"));
+});